#ifndef PLAYERS_H
#define PLAYERS_H



#include "includes.h"
#include "init.h"
#include "ai.h"
#include "gui.h"



//! @brief Player types
enum PlayerType { local, ai, network };



class unit;
class algorithm;



/** @brief Class representing a single player
*
*   \image html players.jpeg
*/
class player
{

public:

	/** @brief Constructor creates new player and sets starting time
	*	@param i player's id
	*	@param n player's name
	*	@param t player's type
	*	@param real_pl if player is real, or simulated
	*/
	player( int i, string n, PlayerType t, bool real_pl = true );

	//! Destructor deletes the player and all his units
	~player();

	/** @brief	Checks if this player is the same with given
	*	@param	p player to check with
	*	@return true if the players are the same, else false
	*/
	bool equals( player* p );
	/**	@brief	Creates deep clone od player including clone of his units
	*	@return	pointer to the clone
	*/
	player* clone();

	/** @brief	Gets remaining time
	*	@return	remaining time
	*/
	int get_time()
	{
		return time;
	};
	/** @brief	Gets palyers id
	*	@return	player's id
	*/
	int get_id()
	{
		return id;
	};
	/** @brief Sets players game time
	*	@param t time to be set
	*/
	void set_time( int t )
	{
		time = t;
	};
	/** @brief	Gets player's type
	*	@return	player's type
	*/
	PlayerType get_type()
	{
		return typ;
	};
	/** @brief Sets player's name
	*	@param n name to be set
	*/
	void set_name( const string& n )
	{
		name = n;
	};
	/** @brief	Gets player's name
	*	@return	player's name
	*/
	string get_name()
	{
		return name;
	};
	/** @brief	Obtains information if the player is in game or not
	*	@return	true, if player is in game, else not
	*/
	bool is_in_game()
	{
		return in_game;
	};
	//! @brief Set's player out of the game (when he has not any units left)
	void set_out()
	{
		in_game = false;
	};
	//! @brief Set's player back to the game (for new game purposes)
	void set_in()
	{
		in_game = true;
	};
	/** @brief	Buys unit from prototypes map
	*	@param	u unit to buy, constraint: u != 0
	*	@param	x x coordinate, where to place new unit, constraint: x < map->size_x
	*	@param	y y coordinate, where to place new unit, constraint: y < map->size_y
	*	@return	true, if the action was successful, else false
	*/
	bool buy_unit( unit* u, unsigned int x, unsigned int y );
	/** @brief	Sells own unit
	*	@param	n unit's id
	*	@return	true, if the action was successful, else false
	*/
	bool sell_unit( unsigned int n );
	/** @brief	If player is in real game, or only in game_state
	*	@return	true, if player is real, else false
	*/
	bool is_real();


	//! vector of player's units
	vector< unit* > units;
	//! pointer to used AI algorithm (when not ai player, pointer == 0)
	algorithm* ai_algorithm;


private:

	//! Player type
	PlayerType typ;
	//! Player's unique id
	int id;
	//! Player's name
	string name;
	//! Player's remeining time in turn, or remaining money while buying units
	int time;
	//! Whether player is still playing, or out
	bool in_game;
	//! If player is in game_state, or in real game
	bool real_player;

};



/** @brief Class containing array of players
*
*   \image html players.jpeg
*/
class players
{

public:

	/**	@brief	Function for obaining the singleton
	*	@return	pointer to the singleton
	*/
	static players* get_instance();

	//! @brief Deletes all players and their units and sets counter to 0
	void rebuild()
	{
		for ( unsigned int i = 0; i < players_count; ++i )
			delete pl[ i ];
		players_count = 0;
	};

	//! @brief Fills the players array with imaginary local unnamed players with id -1
	void fill_players();

	/** @brief Sets player to specified position in the array and handles loaded units
	*	@param p player to set, constraint: p != 0
	*	@param x place where to set him, constraint: x <= "MAX_PL"
	*/
	void set_player( player* p, unsigned int x );
	/** @brief	Gets player from specified place in the array
	*	@param	x place from where to get the player, constraint: x <= "MAX_PL"
	*	@return pointer to the player
	*/
	player* get_player( unsigned int x );
	/** @brief	Gets number of players
	*	@return	Number of players
	*/
	unsigned int get_players_count()
	{
		return players_count;
	};
	/** @brief sets number of players
	*	@param c number of players to set
	*/
	void set_players_count( unsigned int c )
	{
		players_count = c;
	};
	
	/** @brief	Loads players and commands from file for replay
	*	@param	file file, where the players are stored
	*	file structure:
	*	"Number of players"
	*	"Player 1 name"
	*	"Player 1 command 1#Player 1 command 2#... "
	*	"Player 2 name"
	*	"Player 2 command 1#Player 2 command 2#... "
	*	"..."
	*	@return	true, if loading is successful, else false
	*/
	bool load_players( const char* file );

	//! @brief Clears players units and set 
	void clean_players();

	//! array of the players, initial size: "MAX_PL"
	player** pl;

	int x;


private:

	players( int _x ): x( _x )
	{
		pl = new player*[ parameters::get_instance()->game_parameters[ "MAX_PL" ] ];
		players_count = 0;
	};
	players( const players& );
	players& operator=( const players& x );
	//! @brief Deletes players array with all players and their units
	~players()
	{
		for ( unsigned int i = 0; i < players_count; ++i )
			delete pl[ i ];
		delete [] pl;
	};

	//! number of players
	unsigned int players_count;
	
};



#endif